<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Rack DC config</title>
        <script src="https://unpkg.com/vue"></script>
        <style type="text/css">
        .rack {
            width: 30em;
            float: left;
            margin-left: 2em;
            color: #E0E0E0;
            cursor: pointer;
        }
        .config {
            width: 40em;
            float: right;
            margin-right: 2em;
        }
        .rack-t {
            border-collapse: collapse;
            font-family: monospace;
            font-size: 0.9em;
            margin: 0;
            border: 0;
            background-color: #2D2D2D;
        }
        table.rack-t, table.rack-t tr, table.rack-t td {
            border: 1px solid black;
            margin: 0;
            padding: 0;
        }
        .rack-u {
            margin: 0;
            padding: 0;
        }
        td {
            text-align: center;
        }
        td.node-type-1 {
            width: 30em;
        }
        td.node-type-2 {
            width: 15em;
        }
        td.node-type-3 {
            width: 10em;
        }
        table.inner-t {
            height: 5em;
            border-collapse: collapse;
            font-family: monospace;
            font-size: 0.9em;
            width: 100%;
        }
        table.inner-t {
            border: 1px solid black;
        }
        table.inner-t tr, table.inner-t td {
            border: 1px solid black;
        }
        table.inner-t tr {
        }
        .present {
            background-color: #181F90;
        }
        .mp-box {
            height: 100%;
            margin: 1px;
        }
        table.mp-t td {
            width: 10em;
            height: 4.8em;
        }
        #power_shelf_zone, #rmc {
            cursor: not-allowed;
        }
        .config-text {
            resize: none;
            width: 100%;
            height: 25em;
            font-family: monospace;
            font-size: 1.1em;
        }
        td.rmc {
            width: 1em;
        }
        td.psu {
            width: 2em;
        }
        .config-text {
            margin-top: 1em;
        }
        </style>
    </head>
    <body>
        <div id="app">
            <div class="rack">
                <table class="rack-t">
                    <tr>
                        <td rowspan="42">
                            <div class="mp-box">
                                <table class="mp-t">
                                    <template v-for="zone in zones">
                                        <template v-if="zone.t != 'power_shelf'">
                                            <tr :class="['mp', {present: zone.is_present}]" @click="toggle_mp(zone)">
                                                <td>{{ 'RBP/Fan Zone ' + zone.id }}</td>
                                            </tr>
                                        </template>
                                        <template v-else>
                                            <tr id="power_shelf_zone">
                                                <td>X</td>
                                            </tr>
                                        </template>
                                    </template>
                                </table>
                            </div>
                        </td>
                    </tr>

                    <template v-for="u in devices">
                        <template v-if="u.t != 'power_shelf'">
                            <tr :class="['rack-u', {present: u.is_present}]" >
                                <td :class="'node-type-' + node_type" v-for="col in cols" @click="u.is_present = 1 - u.is_present">
                                    {{ u.id + col }}
                                </td>
                            </tr>
                        </template>
                        <template v-else>
                            <tr>
                                <td :colspan="node_type">
                                    <table class="inner-t">
                                        <tr>
                                            <td class="rmc present" id="rmc">RMC</td>
                                            <td :class="['psu', {present: psu.is_present}]" v-for="psu in psus" @click="psu.is_present= 1 - psu.is_present">{{ psu.id }}</td>
                                        </tr>
                                    </table>
                                </td>
                            </tr>
                        </template>
                    </template>
                </table>

            </div>

            <div class="config">
                <div>
                    <input type="radio" v-model="node_type" v-bind:value="1" id="node_type_1" /><label for="node_type_1">1U1N</label>
                    <input type="radio" v-model="node_type" v-bind:value="2" id="node_type_2" /><label for="node_type_2">1U2N</label>
                    <input type="radio" v-model="node_type" v-bind:value="3" id="node_type_3" /><label for="node_type_3">1U3N</label>
                </div>
                <div class="config-text">
                    <textarea class="config-text" v-model="config" ></textarea>
                </div>
            </div>
        </div>
    </body>
    <script type="text/javascript">
        function get_nodes() {
            var n_list = [];
            var nodes_n = 40;
            for (var i=0;i<nodes_n;i++) {
                var u = i +1;
                n_list.push({
                    id: (u < 10 ? '0' : '') + u,
                    is_present: 1,
                })
            }
            return n_list.reverse();
        }
        function get_psus() {
            var p = [];
            var psus_n = 10;
            var g = ['A', 'B']
            for (var i=0;i<g.length;i++) {
                for (var j=0;j<psus_n /2;j++) {
                    p.push({id: g[i] + (j +1), is_present: 1});
                }
            }
            return p;
        }
        function get_mps() {
            var n_list = [];
            var mps_n = 10;
            for (var i=0;i<mps_n;i++) {
                n_list.push({
                    id: i +1,
                    is_present: 1,
                })
            }
            return n_list.reverse();
        }
        function update_present(es, bitmap, reversed, n) {
            var n_list = bitmap2list(bitmap, reversed, n);
            es.forEach(function (node, idx) {node.is_present = n_list[idx]});
        }
        function bitmap2list(bitmap, reversed, n) {
            var bitmap = bitmap.split(' ').map(function(e) {return parseInt(e, 16)});
            bitmap = bitmap.reverse();
            var n_list = [];
            for (var i=0;i<bitmap.length;i++) {
                for (var j=0;j<8;j++) {
                    var is_present = (bitmap[i] >> j) & 1;
                    n_list.push(is_present);
                }
            }
            if (n) {
                n_list = n_list.slice(0, n);
            }
            if (reversed) {
                n_list.reverse();
            }
            return n_list;
        }
        function list2bitmap(n_list, reversed) {
            var n_list = n_list.slice();
            if (reversed) {
                n_list.reverse();
            }
            var bitmap = [];
            var byte = 0;
            var j = 0;
            for (var i=0;i<n_list.length;i++) {
                if ((i % 8) == 0) {
                    if (i > 0) {
                        bitmap.push(byte);
                    }
                    byte = 0;
                    j = 0;
                }
                byte += (n_list[i].is_present & 1) << j;
                j += 1;
            }
            bitmap.push(byte);
            bitmap.reverse();
            return bytes2hex(bitmap);
        }
        function list2amount(n_list) {
            var n_list = n_list.slice();
            var amount = 0;
            for (var i=0;i<n_list.length;i++) {
                amount += n_list[i].is_present;
            }
            return amount;
        }
        function bytes2hex(bytes) {
            return bytes.map(function(byte){return '0x' + (byte < 16 ? '0' : '') + byte.toString(16)}).join(' ');
        }
        var data = {
           node_type: 1,
           all_cols: ['A', 'B', 'C'],
           nodes: get_nodes(),
           psus: get_psus(),
           mps: get_mps()
        };
        var app = new Vue({
            el: '#app',
            data: data,
            computed: {
                config: function() {
                    var ls = [];

                    // node
                    ls.push('Node_Type: ' + this.node_type);
                    var amount = list2amount(this.nodes);
                    ls.push('Node_A_Mount: ' + amount);
                    var location = list2bitmap(this.nodes, true);
                    ls.push('Node_A_Location: ' + location);
                    if (this.node_type > 1) {
                        ls.push('Node_B_Mount: ' + amount);
                        ls.push('Node_B_Location: ' + location);
                    } else {
                        ls.push('Node_B_Mount: ' + 0);
                        ls.push('Node_B_Location: ' + '0x00 0x00 0x00 0x00 0x00');
                    }
                    if (this.node_type > 2) {
                        ls.push('Node_C_Mount: ' + amount);
                        ls.push('Node_C_Location: ' + location);
                    } else {
                        ls.push('Node_C_Mount: ' + 0);
                        ls.push('Node_C_Location: ' + '0x00 0x00 0x00 0x00 0x00');
                    }

                    // mp & fcb
                    amount = list2amount(this.mps);
                    location = list2bitmap(this.mps, true);
                    ls.push('MP_Mount: ' + amount);
                    ls.push('MP_Location: ' + location);
                    ls.push('FCB_Mount: ' + amount);
                    ls.push('FCB_Location: ' + location);

                    // psu
                    ls.push('PSU_Mount: ' + list2amount(this.psus));
                    ls.push('PSU_Location: ' + list2bitmap(this.psus, false));

                    return ls.join('\n');
                },
                cols: function () {
                    return this.all_cols.slice(0, this.node_type);
                },
                devices: function () {
                    return this.nodes.slice(0, 20).concat([{t: 'power_shelf'}]).concat(this.nodes.slice(20));
                },
                zones: function () {
                    return this.mps.slice(0, 5).concat([{t: 'power_shelf'}]).concat(this.mps.slice(5));
                }
            },
            methods: {
                toggle_mp: function(mp) {
                    mp.is_present= 1 - mp.is_present;
                    var idx = (this.mps.length - mp.id) * 4;
                    for (var i=0;i<4;i++) {
                        this.nodes[idx +i].is_present = mp.is_present;
                    }
                }
            }
        });
        update_present(data.nodes, '0x00 0x00 0x0f 0xff 0xf0', true);
        update_present(data.psus, '0x00 0xe7', false);
        update_present(data.mps, '0x00 0x1e', true, 10);

</script>
</html>